package com.gxd.fastdfs.client;

import com.gxd.commons.utils.FTPClientUtil;
import com.gxd.fastdfs.config.FTPConfigProperties;
import com.xiaoleilu.hutool.date.DateUtil;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

/**
 * @Author:gxd
 * @Description:
 * @Date: 10:32 2018/4/24
 * @Modified By:
 */
@Component("ftpManager")
public class FTPManager {
    private static Logger log = LoggerFactory.getLogger(FTPManager.class);
    @Autowired(required = false)
    private FTPConfigProperties ftpConfigProperties;

    /**
     * 上传文件到FTP服务器
     * @param file {@link File}
     * @return 文件上传到服务器的地址
     */
    public String upload(File file) {
        log.debug("【上传文件到FTP服务器】");
        if (file == null) {
            log.warn("【参数file为空】");
            throw new NullArgumentException("file");
        }

        FTPClient ftpClient = connectServer(ftpConfigProperties.getRemotePath());
        // 切换到子目录，按日期，每天创建一个目录
        String subFolder = DateUtil.formatDate(new Date());
        FTPClientUtil.changeWorkingDirectory(subFolder, ftpClient);
        try {
            FTPClientUtil.upload(file, ftpClient);
        } catch (Exception e) {
            log.error("【文件上传失败】", e);
            throw new RuntimeException("文件上传失败");
        } finally {
            FTPClientUtil.closeConnection(ftpClient);
        }
        String uploadedFilePath = ftpConfigProperties.getRemotePath() + File.separator + subFolder
                + File.separator + file.getName();
        log.debug("【文件上传完成】uploadedFilePath = " + uploadedFilePath);
        return uploadedFilePath;
    }

    /**
     * 上传文件到FTP服务器
     * @param file {@link File}
     * @param targetFolder 目标子目录
     * @return 文件上传到服务器的地址
     */
    public String upload(File file, String targetFolder) {
        log.debug("【上传文件到FTP服务器】targetFolder : " + targetFolder);
        if (file == null) {
            log.warn("【参数file为空】");
            throw new NullArgumentException("file");
        }

        FTPClient ftpClient = connectServer(ftpConfigProperties.getRemotePath());
        // 切换到子目录，按日期，每天创建一个目录
        String subFolder = DateUtil.formatDate(new Date());
        FTPClientUtil.changeWorkingDirectory(targetFolder, ftpClient);
        FTPClientUtil.changeWorkingDirectory(subFolder, ftpClient);
        try {
            FTPClientUtil.upload(file, ftpClient);
        } catch (Exception e) {
            log.error("【文件上传失败】", e);
            throw new RuntimeException("文件上传失败");
        } finally {
            FTPClientUtil.closeConnection(ftpClient);
        }
        String uploadedFilePath = ftpConfigProperties.getRemotePath() + File.separator + targetFolder
                + File.separator + subFolder + File.separator + file.getName();
        log.debug("【文件上传完成】uploadedFilePath = " + uploadedFilePath);
        return uploadedFilePath;
    }

    /**
     * 连接服务器
     * @return {@link FTPClient}
     */
    private FTPClient connectServer(String workingDirectory) {
        FTPClient ftpClient = null;
        try {
            // 连接服务器，并切换到对应的项目文件存储目录
            ftpClient = FTPClientUtil.connect(ftpConfigProperties.getHost(), ftpConfigProperties.getPort(),
                    ftpConfigProperties.getUsername(), ftpConfigProperties.getPassword(), workingDirectory);
        } catch (Exception e) {
            log.error("【连接服务器失败】", e);
            throw new RuntimeException("连接服务器失败");
        }
        return ftpClient;
    }

    /**
     * 连接服务器
     * @return {@link FTPClient}
     */
    private FTPClient connectServer() {
        FTPClient ftpClient = null;
        try {
            // 连接服务器，并切换到对应的项目文件存储目录
            ftpClient = FTPClientUtil.connect(ftpConfigProperties.getHost(), ftpConfigProperties.getPort(),
                    ftpConfigProperties.getUsername(), ftpConfigProperties.getPassword());
        } catch (Exception e) {
            log.error("【连接服务器失败】", e);
            throw new RuntimeException("连接服务器失败");
        }
        return ftpClient;
    }

    /**
     * 从服务器获取文件输入流
     * @param fileName 文件路径和名称
     * @return {@link InputStream}
     */
    public InputStream getFileInputStream(String fileName) throws Exception{
        log.debug("【从服务器获取文件输入流】fileName = " + fileName);
        if (StringUtils.isBlank(fileName)) {
            log.warn("【参数fileName为空】");
            throw new NullArgumentException("fileName");
        }
        FTPClient ftpClient = connectServer();
        try {
            String workingDirectory = "";
            InputStream is = null;
            if (fileName.contains("/")) {
                workingDirectory = fileName.substring(0,fileName.lastIndexOf("/"));
            }else{
                throw new Exception("图片路径不对，路径需包含/,从根目录开始，如/picture/2017/test.jpg");
            }
            String directory  = new String(workingDirectory.getBytes("UTF-8"),"iso-8859-1");
            FTPFile[] files = ftpClient.listFiles(directory);
            ftpClient.changeWorkingDirectory(directory);
            for (FTPFile file : files) {
                log.debug("图片编码前名称:"+file.getName());
                String fileNameTemp = new String(file.getName().getBytes("UTF-8"), "iso-8859-1");
                log.debug("图片编码后名称："+fileNameTemp);
                log.debug((file.isDirectory() ? "Folder" : (file.isFile() ? "File" : "")) + " - " + fileName);
                if (file.isFile() && fileNameTemp.equals(fileName)) {
                    // 读取ftp上指定文件的数据
                    is = ftpClient.retrieveFileStream(fileName);
                    return is;
                }
            }
            return is;
           // return FTPClientUtil.retrieveFileStream(fileName, ftpClient);
        } catch (IOException e) {
            log.error("【获取文件流失败】", e);
            throw new RuntimeException("获取文件流失败");
        } finally {
            FTPClientUtil.closeConnection(ftpClient);
        }
    }

    /**
     * 从文件服务器文件下载到应用服务器本地
     * @param fileName 文件路径及名称
     * @param tmpPath 临时文件存放目录
     * @return 存储到临时文件目录的完整路径
     */
    public String downloadFileToLocal(String fileName, String tmpPath) {
        log.debug("【从文件服务器文件下载到应用服务器本地】fileName = " + fileName);
        if (StringUtils.isBlank(fileName)) {
            log.warn("【参数fileName为空】");
            throw new NullArgumentException("fileName");
        }
        FTPClient ftpClient = connectServer();
        String name = getFileNameNoPath(fileName);
        try {
            FTPClientUtil.downLoad(fileName, tmpPath + File.separator + name, ftpClient);
        } catch (Exception e) {
            log.error("【下载文件失败】", e);
            throw new RuntimeException("下载文件失败");
        } finally {
            FTPClientUtil.closeConnection(ftpClient);
        }
        return tmpPath + File.separator + name;
    }

    private String getFileNameNoPath(String fileName){
        String readPath = fileName.substring(fileName.lastIndexOf("/")+1);
        return readPath;
    }

    /**
     * 删除文件服务器的文件
     * @param fileName 文件在文件服务器的地址
     * @throws IOException
     */
    public void delete(String fileName) throws IOException {
        log.debug("【删除文件服务器的文件】fileName = " + fileName);
        FTPClientUtil.delete(fileName, connectServer());
    }

}
